package com.epam.facebook_client.manager;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;

public class HttpClientManager {
	
	public static final String POST_PARAM_SOURCE = "source";
	
	public static final String POST_PARAM_MESSAGE = "message";
	
	public static final String POST_NAME = "name";

	public static final String SERVICE_NAME = "----HTTP_CLIENT_MANAGER----";

	private static final String USER_AGENT_END = ") AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1";

	private static final String USER_AGENT_BUILD = " Build/";

	private static final String SHTRICH = "-";

	private static final String USER_AGENT_DIVIDER = "; ";

	private static final String USER_AGENT_START = "Mozilla/5.0 (Linux; U; Android ";

	public static final int SO_TIMEOUT = 20000;

	/* Constant encoding for http client. */
	private static final String UTF_8 = "UTF-8";

	/* Constant Tag for logging. */
	private static final String TAG = HttpClientManager.class.getSimpleName();

	/* Apache client. */
	private DefaultHttpClient client;

	private String userAgent;

	public static abstract class AbstractRule {

		public abstract boolean isMatch(String url);

		public HttpUriRequest execute(String url) {
			return new HttpGet(url);
		}
	}

	private List<AbstractRule> mListRules;

	public HttpClientManager() {
		// SETS UP PARAMETERS
		HttpParams params = new BasicHttpParams();
		HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
		HttpProtocolParams.setContentCharset(params, UTF_8);
		params.setBooleanParameter("http.protocol.expect-continue", false);
		HttpConnectionParams.setConnectionTimeout(params, SO_TIMEOUT);
		HttpConnectionParams.setSoTimeout(params, SO_TIMEOUT);

		// REGISTERS SCHEMES FOR BOTH HTTP AND HTTPS
		SchemeRegistry registry = new SchemeRegistry();
		registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
		final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
		sslSocketFactory.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
		registry.register(new Scheme("https", sslSocketFactory, 443));
		ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry);
		client = new DefaultHttpClient(manager, params);
		userAgent = USER_AGENT_START + android.os.Build.VERSION.RELEASE + USER_AGENT_DIVIDER
				+ Locale.getDefault().getLanguage() + SHTRICH + Locale.getDefault().getCountry()
				+ USER_AGENT_DIVIDER + android.os.Build.DEVICE + USER_AGENT_BUILD + android.os.Build.ID
				+ USER_AGENT_END;
		Log.d(TAG, userAgent);
	}

	public void addRule(AbstractRule rule) {
		if (mListRules == null) {
			mListRules = new ArrayList<AbstractRule>();
		}
		mListRules.add(rule);
	}

	public String loadAsString(String url) throws ClientProtocolException, IOException {
		HttpUriRequest request = generateRequest(url);
		if (request == null) {
			request = new HttpGet(url);
		}
		return loadAsString(request);
	}

	private String loadAsString(HttpUriRequest request) throws ClientProtocolException, IOException {
		HttpResponse response = client.execute(request);
		StringBuffer strBuffer = new StringBuffer();
		String s = null;
		BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
		while ((s = br.readLine()) != null) {
			strBuffer.append(s);
		}
		br.close();
		return strBuffer.toString();
	}

	public Bitmap loadAsBitmap(String url) throws IOException {
		HttpUriRequest request = generateRequest(url);
		if (request == null) {
			request = new HttpGet(url);
		}
		return loadAsBitmap(request);
	}

	private Bitmap loadAsBitmap(HttpUriRequest request) throws IOException {
		HttpResponse response = client.execute(request);
		BufferedInputStream br = new BufferedInputStream(response.getEntity().getContent());
		Bitmap bitmap = BitmapFactory.decodeStream(br);
		br.close();
		return bitmap;
	}

	public String postString(String url, Map<String, String> params) throws ClientProtocolException,
			IOException {
		HttpUriRequest request = generateRequest(url);
		if (request == null) {
			request = new HttpPost(url);
		}
		return postString(request, params);
	}

	private String postString(HttpUriRequest request, Map<String, String> params)
			throws ClientProtocolException, IOException {
		HttpPost post = (HttpPost) request;
		List<NameValuePair> parameters = new ArrayList<NameValuePair>();
		for (Entry<String, String> param : params.entrySet()) {
			parameters.add(new BasicNameValuePair(param.getKey(), param.getValue()));
		}
		UrlEncodedFormEntity entity = new UrlEncodedFormEntity(parameters);
		post.setEntity(entity);
		HttpResponse response = client.execute(post);
		StringBuffer strBuffer = new StringBuffer();
		String s = null;
		InputStreamReader inputStreamReader = null;
		BufferedReader br = null;
		try {
			inputStreamReader = new InputStreamReader(response.getEntity().getContent());
			br = new BufferedReader(inputStreamReader);
			while ((s = br.readLine()) != null) {
				strBuffer.append(s);
			}
		} finally {
			if (br != null) {
				br.close();
			}
			if (inputStreamReader != null) {
				inputStreamReader.close();
			}
		}
		Log.i(TAG, "PATH: " + request.getURI().getPath());
		return strBuffer.toString();
	}

	public String postImage(String url, Map<String, String> params) {
		HttpUriRequest request = generateRequest(url);
		if (request == null) {
			request = new HttpPost(url);
		}
		return postImage(request, params);
	}


	
	private String postImage(HttpUriRequest request, Map<String, String> params) {
		HttpContext localContext = new BasicHttpContext();
		HttpPost httpPost = (HttpPost) request;
		List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
		nameValuePairs.add(new BasicNameValuePair(POST_PARAM_SOURCE, params.get(POST_PARAM_SOURCE)));
		try {
			MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);

			for (int index = 0; index < nameValuePairs.size(); index++) {
				if (nameValuePairs.get(index).getName().equalsIgnoreCase(POST_PARAM_SOURCE)) {
					entity.addPart(nameValuePairs.get(index).getName(), new FileBody(new File(nameValuePairs.get(index).getValue())));
					if (params.containsKey(POST_PARAM_MESSAGE)) {
						entity.addPart(POST_PARAM_MESSAGE, new StringBody(params.get(POST_PARAM_MESSAGE)));
					}
				}
			}

			httpPost.setEntity(entity);

			HttpResponse response = client.execute(httpPost, localContext);

			StringBuffer strBuffer = new StringBuffer();
			String s = null;
			InputStreamReader inputStreamReader = null;
			BufferedReader br = null;
			try {
				inputStreamReader = new InputStreamReader(response.getEntity().getContent());
				br = new BufferedReader(inputStreamReader);
				while ((s = br.readLine()) != null) {
					strBuffer.append(s);
				}
			} finally {
				if (br != null) {
					br.close();
				}
				if (inputStreamReader != null) {
					inputStreamReader.close();
				}
			}
			Log.i(TAG, "Response: " + strBuffer.toString());
			return strBuffer.toString();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return null;
	}

	private HttpUriRequest generateRequest(String url) {
		HttpUriRequest request = null;
		if (mListRules != null && !mListRules.isEmpty()) {
			for (AbstractRule rule : mListRules) {
				if (rule.isMatch(url)) {
					request = rule.execute(url);
				}
			}
		}
		return request;
	}

	public static HttpClientManager get(Context context) {
		return (HttpClientManager) context.getApplicationContext().getSystemService(SERVICE_NAME);
	}
}
